package com.liveinstars.im.domain.manager.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.liveinstars.im.domain.dao.mapper.ChatGroupMemberMapper;
import com.liveinstars.im.domain.dao.model.ChatGroupMember;
import com.liveinstars.im.domain.manager.ChatGroupMemberManager;
import com.onepiece.shipelves.common.constant.Constant;
import com.onepiece.shipelves.common.enums.SystemExceptionEnum;
import com.onepiece.shipelves.common.exception.DatabaseException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 聊天群成员组织 服务实现类
 * </p>
 *
 * @author 8btc
 * @since 2020-03-31
 */
@Service
public class ChatGroupMemberManagerImpl extends ServiceImpl<ChatGroupMemberMapper, ChatGroupMember> implements ChatGroupMemberManager {

    private final static Logger logger = LoggerFactory.getLogger(ChatGroupMemberManagerImpl.class);

    @Resource
    private ChatGroupMemberMapper chatGroupMemberMapper;

    @Override
    public List<Long> listChatGroupIdByUserIdAndGroupType(Long userId, Integer groupType) {

        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("group_type", groupType).select("chat_group_id");
            return this.listObjs(queryWrapper, object -> Long.valueOf(String.valueOf(object)));
        } catch (Exception e) {
            logger.error("listChatGroupIdByUserIdAndGroupType userId:{} groupType:{} errorMsg:{}",
                    userId, groupType, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }

    }

    @Override
    public List<ChatGroupMember> listByUserIdAndGroupType(Long userId, Integer groupType) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("group_type", groupType);
            return this.list(queryWrapper);
        } catch (Exception e) {
            logger.error("listChatGroupIdByUserIdAndGroupType userId:{} groupType:{} errorMsg:{}",
                    userId, groupType, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public List<ChatGroupMember> listUnshieldMemberByChatGroupId(Long chatGroupId) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId).eq("shield", Constant.NO);
            return this.list(queryWrapper);
        } catch (Exception e) {
            logger.error("listUnshieldMemberByChatGroupId chatGroupId:{} errorMsg:{}",
                    chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }

    }

    @Override
    public List<ChatGroupMember> listMemberByChatGroupId(Long chatGroupId) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId);
            return this.list(queryWrapper);
        } catch (Exception e) {
            logger.error("listMemberByChatGroupId chatGroupId:{} errorMsg:{}",
                    chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public ChatGroupMember getChatGroupMemberByGroupIdAndUserId(Long chatGroupId, Long userId) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId).eq("user_id", userId);
            List<ChatGroupMember> list = this.list(queryWrapper);
            if (CollectionUtils.isNotEmpty(list)) {
                return list.get(0);
            } else {
                return null;
            }
        } catch (Exception e) {
            logger.error("getChatGroupMemberByGroupIdAndUserId chatGroupId:{} userId:{} errorMsg:{}",
                    chatGroupId, userId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void deleteMemberByChatGroupIdAndUserId(Long chatGroupId, Long userId) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId).eq("user_id", userId);
            this.remove(queryWrapper);
        } catch (Exception e) {
            logger.error("deleteMemberByChatGroupIdAndUserId chatGroupId:{} userId:{} errorMsg:{}",
                    chatGroupId, userId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void deleteMemberByChatGroupId(Long chatGroupId) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId);
            this.remove(queryWrapper);
        } catch (Exception e) {
            logger.error("deleteMemberByChatGroupIdAndUserId chatGroupId:{} errorMsg:{}",
                    chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public int countByChatGroupId(Long chatGroupId) {
        QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("chat_group_id", chatGroupId);
        return this.count(queryWrapper);
    }

    @Override
    public void deleteMemberByChatGroupIdAndUserIdList(Long chatGroupId, List<Long> userIdList) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId).in("user_id", userIdList);
            this.remove(queryWrapper);
        } catch (Exception e) {
            logger.error("deleteMemberByChatGroupIdAndUserIdList chatGroupId:{} userIdList:{} errorMsg:{}",
                    chatGroupId, userIdList.toString(), e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public Map<Long, Integer> mapMemberCountByChatGroupIdList(List<Long> chatGroupIdList) {
        try {
            Map<Long, Integer> chatGroupMemberCountMap = Maps.newHashMap();
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("chat_group_id", chatGroupIdList).groupBy("chat_group_id").select("chat_group_id", "count(*) as count");
            List<Map<String, Object>> list = this.listMaps(queryWrapper);
            list.stream().filter(Objects::nonNull)
                    .forEach(map -> chatGroupMemberCountMap.put(Long.valueOf(String.valueOf(map.get("chat_group_id"))), Integer.valueOf(String.valueOf(map.get("count")))));
            return chatGroupMemberCountMap;
        } catch (Exception e) {
            logger.error("mapMemberCountByChatGroupIdList chatGroupIdList:{} errorMsg:{}",
                    chatGroupIdList.toString(), e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void updateShield(Long userId, Long chatGroupId, boolean shield) {
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("chat_group_id", chatGroupId);
            ChatGroupMember chatGroupMember = new ChatGroupMember();
            chatGroupMember.setShield(shield);
            chatGroupMember.setShieldTime(Long.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"))).intValue());
            this.update(chatGroupMember, queryWrapper);
        } catch (Exception e) {
            logger.error("updateShield params:{} errorMsg:{}",
                    "userId="+userId+", chatGroupId="+ chatGroupId + ", shield=" + shield, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void batchSaveFriendMember(List<ChatGroupMember> list, Long chatGroupId) {
        if (chatGroupId == null) {
            throw new DatabaseException(SystemExceptionEnum.MISSING_REQUEST_PARAM);
        }
        try {
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("chat_group_id", chatGroupId);
            this.remove(queryWrapper);
            this.saveBatch(list);
        } catch (Exception e) {
            logger.error("batchSaveFriendMember params:{} errorMsg:{}",
                    "list="+ JSON.toJSONString(list)+", chatGroupId="+ chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void batchSaveMember(List<ChatGroupMember> list, Long chatGroupId) {
        List<ChatGroupMember> chatGroupMemberList = listMemberByChatGroupId(chatGroupId);
        try {
            if (CollectionUtils.isNotEmpty(chatGroupMemberList)) {
                List<Long> userIdList = chatGroupMemberList.stream().map(ChatGroupMember::getUserId).collect(Collectors.toList());
                list = list.stream().filter(new Predicate<ChatGroupMember>() {
                    @Override
                    public boolean test(ChatGroupMember chatGroupMember) {
                        return userIdList.indexOf(chatGroupMember.getUserId()) < 0;
                    }
                }).collect(Collectors.toList());
            }
            this.saveBatch(list);
        } catch (Exception e) {
            logger.error("batchSaveFriendMember params:{} errorMsg:{}",
                    "list="+ JSON.toJSONString(list)+", chatGroupId="+ chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void saveChatGroupMember(ChatGroupMember chatGroupMember) {
        try {
            chatGroupMember.setNoDisturbing(false);
            chatGroupMember.setShield(false);
            this.save(chatGroupMember);
        } catch (Exception e) {
            logger.error("saveChatGroupMember params:{} errorMsg:{}",
                    "chatGroupMember="+ JSON.toJSONString(chatGroupMember), e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void updateReverseShieldByUserIdAndChatGroupId(Long userId, Long chatGroupId) {
        try {
            chatGroupMemberMapper.updateReverseShieldByUserIdAndChatGroupId(userId, chatGroupId);
        } catch (Exception e) {
            logger.error("updateReverseShieldByUserIdAndChatGroupId params:{} errorMsg:{}",
                    "userId="+ userId + " chatGroupId=" + chatGroupId, e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }

    @Override
    public void updateByUserIdAndChatGroupId(ChatGroupMember chatGroupMember, Long userId, Long chatGroupId) {
        try {
            //id不能被修改
            chatGroupMember.setId(null);
            QueryWrapper<ChatGroupMember> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("chat_group_id", chatGroupId);
            this.update(chatGroupMember, queryWrapper);
        } catch (Exception e) {
            logger.error("updateShield params:{} errorMsg:{}",
                    "userId="+userId+", chatGroupId="+ chatGroupId + ", chatGroupMember=" + JSON.toJSONString(chatGroupMember), e.getMessage(), e);
            throw new DatabaseException(SystemExceptionEnum.MYSQL_OPERATING_ERROR);
        }
    }
}
